// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/formats/mpeg/adts_stream_parser.h"

#include <stddef.h>

#include "build/build_config.h"
#include "media/base/media_log.h"
#include "media/formats/mp4/aac.h"
#include "media/formats/mpeg/adts_constants.h"

namespace media {

static const uint32_t kADTSStartCodeMask = 0xfff00000;

ADTSStreamParser::ADTSStreamParser()
    : MPEGAudioStreamParserBase(kADTSStartCodeMask, kCodecAAC, 0)
{
}

ADTSStreamParser::~ADTSStreamParser() { }

int ADTSStreamParser::ParseFrameHeader(const uint8_t* data,
    int size,
    int* frame_size,
    int* sample_rate,
    ChannelLayout* channel_layout,
    int* sample_count,
    bool* metadata_frame,
    std::vector<uint8_t>* extra_data) const
{
    DCHECK(data);
    DCHECK_GE(size, 0);

    if (size < kADTSHeaderMinSize)
        return 0;

    BitReader reader(data, size);
    int sync;
    int version;
    int layer;
    int protection_absent;
    int profile;
    size_t sample_rate_index;
    size_t channel_layout_index;
    int frame_length;
    size_t num_data_blocks;
    int unused;

    if (!reader.ReadBits(12, &sync) || !reader.ReadBits(1, &version) || !reader.ReadBits(2, &layer) || !reader.ReadBits(1, &protection_absent) || !reader.ReadBits(2, &profile) || !reader.ReadBits(4, &sample_rate_index) || !reader.ReadBits(1, &unused) || !reader.ReadBits(3, &channel_layout_index) || !reader.ReadBits(4, &unused) || !reader.ReadBits(13, &frame_length) || !reader.ReadBits(11, &unused) || !reader.ReadBits(2, &num_data_blocks) || (!protection_absent && !reader.ReadBits(16, &unused))) {
        return -1;
    }

    DVLOG(2) << "Header data :" << std::hex
             << " sync 0x" << sync
             << " version 0x" << version
             << " layer 0x" << layer
             << " profile 0x" << profile
             << " sample_rate_index 0x" << sample_rate_index
             << " channel_layout_index 0x" << channel_layout_index;

    const int bytes_read = reader.bits_read() / 8;
    if (sync != 0xfff || layer != 0 || frame_length < bytes_read || sample_rate_index >= kADTSFrequencyTableSize || channel_layout_index >= kADTSChannelLayoutTableSize) {
        if (media_log()) {
            MEDIA_LOG(DEBUG, media_log())
                << "Invalid header data :" << std::hex << " sync 0x" << sync
                << " version 0x" << version << " layer 0x" << layer
                << " sample_rate_index 0x" << sample_rate_index
                << " channel_layout_index 0x" << channel_layout_index;
        }
        return -1;
    }

    if (sample_rate)
        *sample_rate = kADTSFrequencyTable[sample_rate_index];

    if (frame_size)
        *frame_size = frame_length;

    if (sample_count)
        *sample_count = (num_data_blocks + 1) * kSamplesPerAACFrame;

    if (channel_layout)
        *channel_layout = kADTSChannelLayoutTable[channel_layout_index];

    if (metadata_frame)
        *metadata_frame = false;

    if (extra_data) {
        // See mp4::AAC::Parse() for details. We don't need to worry about writing
        // extensions since we can't have extended ADTS by this point (it's
        // explicitly rejected as invalid above).
        DCHECK_NE(sample_rate_index, 15u);

        // The following code is written according to ISO 14496 Part 3 Table 1.13 -
        // Syntax of AudioSpecificConfig.
        const uint16_t esds = (((((profile + 1) << 4) + sample_rate_index) << 4) + channel_layout_index)
            << 3;
        extra_data->push_back(esds >> 8);
        extra_data->push_back(esds & 0xFF);
        if (media_log())
            DCHECK(mp4::AAC().Parse(*extra_data, media_log()));
    }

    return bytes_read;
}

} // namespace media
